前兩日說到了軟體設計的準則,今天配合實際案例說明架構設計原則
合成複用原則(Composition Over Inheritance)
軟體設計核心概念除了SOLID原則原則外,還有一個合成復用原則,旨在強調類別間的依賴關係應該避免繼承,而是盡量用組合方式將類別擴充新功能,試想當一個類別的方法出現太多判斷式,或是行數接近千行,這時候適當的處理方式就是拆分模組或是工具類,放入原有的方法實作中來完成邏輯
依賴性注入(Dependency Inject)
與合成複用原則類似實作概念為依賴性注入,這個手法存在的目的就是由外部來改變類別依賴的模組,是昨日提到的依賴反轉原則,具體實現概念,現在透過範例來說明依賴性注入
先來透過程式定義主角-喜歡吃荷包蛋的布偶貓
class CrazyPuppetCat {
// 打印喜歡的食物
public void favorateFood() {
System.out.println("喜歡瘋狂吃荷包蛋");
}
}
有一天布偶貓肚子餓了想要吃荷包蛋,於是打電話請烏龜好朋友外送,這時候程式碼會改動成這樣...
// 烏龜
class Turtle {
private String food = "荷包蛋";
private String name = "烏龜";
public String getName() {
return name;
}
// 打印發送的食物
public String givenFood() {
return food;
}
}
class CrazyPuppetCat {
// 烏龜外送員
private Turtle foodSender = new Turtle;
public void getFood() {
String senderName = foodSender.getName();
String food = foodSender.givenFood();
System.out.printf(
"布偶貓從 %s 手中拿到宵夜 %s\n",
senderName, food);
}
}
接著用瘋狂布偶貓的實體化物件執行 getFood 方法,打印出布偶貓透過依賴的烏龜實例,取得宵夜的文字
不同依賴對象可能遇到的問題
那麼問題來了,當瘋狂的布偶貓想要找貓頭鷹、鴨子來送荷包蛋,每次就要修改 foodSender屬性,這個動作違反了開放封閉原則,以及依賴反轉原則,為了解決這個問題必須將程式碼進行改寫
來個 Interface 規範外送員要有的行為
interface FoodSender {
String givenFood();
String getName();
}
在建立其他動物類別
// 貓頭鷹類別
class Owl implements FoodSender {
private String food = "荷包蛋";
private String name = "貓頭鷹";
@Override
public String getName() {
return name;
}
// 打印發送的食物
@Override
public String givenFood() {
return food;
}
}
// 鴨子類別
class Duck implements FoodSender {
private String food = "荷包蛋";
private String name = "鴨子";
@Override
public String getName() {
return name;
}
// 打印發送的食物
@Override
public String givenFood() {
return food;
}
}
布偶貓類別的外送員屬性調整參考型別,並建立新方法設定依賴的外送員
// CrazyPuppetCat.java
// 將屬性修改成外送員介面
private FoodSender foodSender; // 外送員
// 新增設定外送員的方法
public void setFoodSend(FoodSender _foodSender) {
foodSender = _foodSender;
}
// 在 main方法 實際運行程式碼看輸出
public static void main(String[] args){
CrazyPuppetCat cat = new CrazyPuppetCat();
cat.setFoodSend(new Turtle());
cat.getFood(); // 布偶貓從 烏龜手中拿到消夜 荷包蛋
cat.setFoodSend(new Duck());
cat.getFood(); // 布偶貓從 鴨子 手中拿到宵夜 荷包蛋
cat.setFoodSend(new Owl());
cat.getFood(); // 布偶貓從 貓頭鷹 手中拿到宵夜 荷包蛋
}
從測試結果可以發現調整後的做法能做到,不修改布偶貓類別的情況下將依賴的外送員替掉,這個手法叫做「依賴性注入」,利用各種方式變更使用到的實例物件,常見作法有透過建構子、方法(同範例)以及控制反轉(IOC)容器注入實體的容器,Spring Boot則是利用了IOC容器,實現依賴性注入